#!/bin/sh
# - runtime
# - rw
# - bs
# - ioengine
# - iodepth
# - direct
# - test_size
# - nr_task
# - fallocate
# - time_based
# - raw_disk
# - invalidate
# - nr_files
# - filesize
# - io_size
# - file_service_type
# - random_distribution
# - numa_mem_policy
# - numa_cpu_nodes
# - pre_read
# - rwmixread
# - ioscheduler
# - ramp_time
# - loops
# - cpuload
# - donorname
# - test_filename

. $LKP_SRC/lib/reproduce-log.sh
. $LKP_SRC/lib/common.sh
. $LKP_SRC/lib/unit.sh
. $LKP_SRC/lib/debug.sh

[ -n "$test_size" ] || die "test_size must be specified for fio"

test_size=$(to_byte $test_size)
size=$((test_size / nr_task))

: ${bs:=4k}
: ${ioengine:=sync}
: ${runtime:=300}
: ${rw:=write}
: ${iodepth:=32}
: ${direct:=0}
: ${fallocate:=posix}
: ${invalidate:=1}
: ${nr_task:=1}
: ${nr_files:=1}
: ${filesize:=$size}
: ${io_size:=$size}
: ${file_service_type:=roundrobin}
: ${random_distribution:=random}
: ${pre_read:=0}
: ${ioscheduler:=none}
: ${ramp_time:=0}
: ${loops:=0}

direct=$(parse_bool $direct)
raw_disk=$(parse_bool $raw_disk)
pre_read=$(parse_bool $pre_read)

if [ "$raw_disk" = 1 ]; then
	storages=$partitions
else
	storages=$mount_points
fi
[ -z "$storages" ] && die "storages is empty, we can't get jobs_per_storage and nr_task_remain"
for storage in $storages
do
	mnt_point=$(stat -c %m $(readlink -f $storage))
	available_storage_size=$(df -k | awk '{print $4" "$NF}' | grep $mnt_point$ | awk '{print $1}')
	[ $available_storage_size ] || die "storage $storage doesn't mounted"
	available_storage_size=$(to_byte ${available_storage_size}k)

	require_size=$test_size
	df | grep $mnt_point$ | awk '{print $1}' | grep -q /dev/pmem && require_size=$size
	[ $available_storage_size -lt $require_size ] && die "storage $storage available size: $available_storage_size < $require_size"
done

nr_storages=$(echo $storages | wc -w)
jobs_per_storage=$((nr_task / nr_storages))

nr_task_remain=$((nr_task % nr_storages))
[ "$nr_task_remain" -ne 0 ] && die "nr_task % nr_storages = $nr_task_remain"

create_task="\
[global]
bs=$bs
ioengine=$ioengine
iodepth=$iodepth
size=$size
nr_files=$nr_files
filesize=$filesize
direct=$direct
runtime=$runtime
invalidate=$invalidate
fallocate=$fallocate
io_size=$io_size
file_service_type=$file_service_type
random_distribution=$random_distribution
allow_mounted_write=1
group_reporting
create_only=1
pre_read=$pre_read
"

params="ramp_time loops"
for param in $params; do
	param_value="$(eval echo '$'$param)"
	if [ "$param_value" != 0 ]; then
		create_task="\
$create_task
$param=$param_value"
	fi
done

if [ "$ioscheduler" != "none" ]; then
	create_task="\
$create_task
ioscheduler=$ioscheduler"
fi

if parse_bool -q "$time_based"; then
	create_task="\
$create_task
time_based
"
fi

if parse_bool -q "$cpuload"; then
	create_task="
$create_task
cpuload=$cpuload
"
fi

if parse_bool -q "$donorname"; then
       create_task="
$create_task
donorname=$donorname
"
fi

[ -n "$rwmixread" ] && [ "$rw" == "randrw" ] && rwmixread_setup="rwmixread=$rwmixread"

parse_numa_mem_policy()
{
	if [ -z "$numa_mem_policy" ]; then
		__numa_mem_policy_setup="none"
	elif [ "${numa_mem_policy%:even}" != "$numa_mem_policy" ]; then
		__numa_mem_policy_mode="${numa_mem_policy%:even}"
		__numa_mem_policy_setup="even"
	else
		__numa_mem_policy_setup="orig"
	fi
}

__numa_mem_policy()
{
	__seq_no=$1

	case "$__numa_mem_policy_setup" in
		none)
		;;
		even)
			echo "numa_mem_policy=${__numa_mem_policy_mode}:$((__seq_no%nr_node))"
			;;
		orig)
			echo "numa_mem_policy=${numa_mem_policy}"
			;;
	esac
}

parse_numa_cpu_nodes()
{
	if [ -z "$numa_cpu_nodes" ]; then
		__numa_cpu_nodes_setup="none"
	elif [ "${numa_cpu_nodes%even*}" != "$numa_cpu_nodes" ]; then
		__numa_cpu_nodes_setup="even"
	else
		__numa_cpu_nodes_setup="orig"
	fi
}

__numa_cpu_nodes()
{
	__seq_no=$1

	case "$__numa_cpu_nodes_setup" in
		none)
		;;
		even)
			echo "numa_cpu_nodes=$((__seq_no%nr_node))"
			;;
		orig)
			echo "numa_cpu_nodes=${numa_cpu_nodes}"
			;;
	esac
}

parse_numa_mem_policy
parse_numa_cpu_nodes

no=0
for storage in $storages; do
	if [ "$raw_disk" = 1 ]; then
		storage_setup="filename=$storage"
	elif [ -n "$test_filename" ]; then
		storage_setup="filename=$test_filename"
	else
		storage_setup="directory=$storage"
	fi
        if [ "$ioengine" = "sg" ]; then
                dev_src=`findmnt $storage -no source`
                storage_setup="filename=$dev_src\nallow_mounted_write=1"
        fi
	create_task="\
$create_task
[task_$no]
rw=$rw
$storage_setup
numjobs=$jobs_per_storage
$rwmixread_setup
name=rw_${rw}_bs_${bs}_jobname
$(__numa_mem_policy $no)
$(__numa_cpu_nodes $no)
"
	no=$((no+1))
done

echo -n "$create_task" | sed '/create_only/d' > $TMP_RESULT_ROOT/fio.task
echo -n "$create_task" | fio --output-format=json - > /dev/null
